package jwt

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	uuid "github.com/lithammer/shortuuid/v4"
	"github.com/redis/go-redis/v9"
	"strings"
	"time"
)

const (
	//access_key
	AtKey = "R9zsqdUm77WKcbM68UQUuxVsHSpTCwgK"
	//refresh_key
	RtKey = "k6CswdUm32pKcbM68UQUUOVsHSpTCwgK"
)

type RedisJWTHandler struct {
	Cmd redis.Cmdable
}

func NewRedisJWTHandler(cmd redis.Cmdable) Handler {
	return &RedisJWTHandler{Cmd: cmd}
}

func (j *RedisJWTHandler) SetLoginToken(ctx *gin.Context, uid int64) error {
	ssid := uuid.New()
	err := j.SetJWTToken(ctx, uid, ssid)
	if err != nil {
		return err
	}
	err = j.SetRefreshToken(ctx, uid, ssid)
	if err != nil {
		return err
	}
	return nil
}

func (j *RedisJWTHandler) SetJWTToken(ctx *gin.Context, uid int64, ssid string) error {
	uc := UserClaims{
		Uid:       uid,
		Ssid:      ssid,
		UserAgent: ctx.GetHeader("User-Agent"),
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * 30)),
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS512, uc)
	tokenStr, err := token.SignedString([]byte(AtKey))
	if err != nil {
		return err
	}

	//返回头里添加
	ctx.Header("x-jwt-token", tokenStr)
	return nil
}
func (j *RedisJWTHandler) SetRefreshToken(ctx *gin.Context, uid int64, ssid string) error {
	uc := RefreshClaims{
		Uid:  uid,
		Ssid: ssid,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24 * 7)),
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS512, uc)
	tokenStr, err := token.SignedString([]byte(RtKey))
	if err != nil {
		return err
	}

	//返回头里添加
	ctx.Header("x-refresh-token", tokenStr)
	return nil
}
func (j *RedisJWTHandler) ClearToken(ctx *gin.Context) error {
	ctx.Header("x-jwt-token", "")
	ctx.Header("x-refresh-token", "")

	val, _ := ctx.Get("claims")
	claims, ok := val.(*UserClaims)
	if !ok {
		return errors.New("val 不匹配")
	}
	return j.Cmd.Set(ctx, fmt.Sprintf("users:ssid:%s", claims.Ssid),
		"", time.Hour*24*7).Err()
}
func (j *RedisJWTHandler) CheckSession(ctx *gin.Context, ssid string) int64 {
	//存在已经退出的ssid
	cnt, _ := j.Cmd.Exists(ctx, fmt.Sprintf("users:ssid:%s"), ssid).Result()
	return cnt
}
func (j *RedisJWTHandler) ExtractToken(ctx *gin.Context) string {
	authCode := ctx.GetHeader("Authorization")
	segs := strings.Split(authCode, " ")
	if len(segs) != 2 {
		return ""
	}
	return segs[1]
}

type RefreshClaims struct {
	Uid  int64
	Ssid string
	jwt.RegisteredClaims
}

type UserClaims struct {
	Uid       int64
	Ssid      string
	UserAgent string
	jwt.RegisteredClaims
}
